package main

import "fmt"
// 颜色板，将print打印成特殊颜色，方便查看对应的输出结果
const (
    TextBlack = iota + 30
    TextRed
    TextGreen
    TextYellow
    TextBlue
    TextMagenta
    TextCyan
    TextWhite
)

//将说明打印成蓝色
func debug(s string) {
    fmt.Printf("\x1b[0;%dm%s\x1b[0m\n", TextBlue, s)
}

func test2() {
    debug("test2():\t\t4-> 压栈 5th , 6th")
    defer fmt.Println("5th defer")
    defer fmt.Println("6th defer")
    debug("\t\t\t4<- 出栈 6th,5th")
    return
}

func test1() {
    debug("test1():\t3-> 压栈 test2()")
    defer test2()
    defer fmt.Println("3rd defer")
    defer fmt.Println("4th defer")
    debug("\t\t3<- 出栈 4th,3rd,test2()")
    return
}

func add(a int) int {
    debug("1.3，进入add")
    a = a + 5

    debug("1.4，打印add()结果a1, 并返回")
    fmt.Println("defer a1 = ", a)
    return a
}
func f2() (a int) {
    debug("1.1，进入f2()")
    debug("1.2，defer压栈：先算参数add(a), 记为a1，将println(a1)压栈")

    defer fmt.Println(add(a))
    a += 3

    debug("1.5，打印f2()结果,记为a2，并返回")
    fmt.Println("f2 a2 = ", a)

    debug("1.6，执行defer printf(a1)")
    return a
}
/*
先压栈，将func()压栈时，只压入他的参数和他本身，
而此时函数中print的参数i还不确定，因为还没有执行行这里，
只有在调用执行print函数时，将print压榨时才确定，并将i压入栈。这时，i已经算完，是8
最后执行8个print(i)
*/
func deferFunc() {
    debug("for循环中的defer func()")
    for i := 0; i < 8; i++ {
        defer func() {
            fmt.Print(i)
        }()
    }

}

// 先压栈，print压栈时，会将print和他的参数i同时压入,因此，此时i值是确定的，结果是倒序76543210
func deferFmt() {
    debug("for循环中的defer fmt.print")
    for i := 0; i < 8; i++ {
        defer fmt.Print(i)
    }
}
func deferReturnNum() (result int) {
    debug("0, deferReturnNum(): func()压栈")
    defer func() {
        debug("0.2, func()中计算result=result*7")
        result *= 7
    }()
    debug("0.1, defer原理：1，赋值result=6; 2，defer函数func()出栈; 3 返回result")
    return 6

}

func main() {
    r := deferReturnNum()
    fmt.Println(r)//r=42

    deferFmt()
    fmt.Print("\n")
    deferFunc()
    fmt.Print("\n")

    debug("1，调用fmt.println(f2)")
    fmt.Println(f2())
    debug("1.7，上述打印的值为a2")

    debug("2-> 压栈 test1, 1st, 2nd")
    defer test1()
    defer fmt.Println("1st defer")
    defer fmt.Println("2nd defer")

    debug("2 <- 出栈 2nd,1st,test1()->")
}


